package org.vacoor.xqq.core.msg.chatmsg;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.xqq.core.util.Jacksons;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 联系人 / 群 / 讨论组 消息体
 * <p/>
 * 在 QQ 中内容样式也作为一个消息体的元素出现
 * 在发送时 样式应该为最后一个片段, 接收时样式应该是第一个片段
 * <p/>
 * <p/>
 * User: Vacoor
 */

@JsonSerialize(using = MsgBody.MsgBodySerializer.class)
@JsonDeserialize(using = MsgBody.MsgBodyDeserializer.class)
public class MsgBody implements Iterable<MsgElement> {
    private MsgStyle msgStyle = MsgStyle.DEFAULT_STYLE;
    private List<MsgElement> elements = new ArrayList<MsgElement>();

    public MsgStyle getMsgStyle() {
        return msgStyle;
    }

    public void setMsgStyle(MsgStyle msgStyle) {
        this.msgStyle = msgStyle;
    }

    public MsgBody addElement(MsgElement fragment) {
        this.elements.add(fragment);
        return this;
    }

    public List<MsgElement> getElements() {
        return elements;
    }

    public void setElements(List<MsgElement> elements) {
        this.elements = elements;
    }

    @Override
    public Iterator<MsgElement> iterator() {
        return elements.iterator();
    }

    @Override
    public String toString() {
        StringBuilder str = new StringBuilder();
        str.append(getClass().getCanonicalName())
                .append(":{")
                .append(msgStyle)
                .append(",elements:[");
        for (MsgElement e : elements) {
            str.append(e);
        }

        return str.append("]}").toString();
    }

    // ------------------------------------------------------

    /**
     * 消息体反序列化器
     */
    static final class MsgBodyDeserializer extends JsonDeserializer<MsgBody> {
        private final Logger logger = LoggerFactory.getLogger(MsgBodyDeserializer.class);

        @Override
        public MsgBody deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            MsgBody msgBody = new MsgBody();
            JsonNode tree = jp.readValueAsTree();
            if (tree.isArray()) {
                for (JsonNode node : tree) {
                    // 文本消息
                    if (node.isTextual()) {
                        msgBody.addElement(MsgElement.createTextElement(node.asText()));
                    } else if (node.isArray() && node.size() > 1) {
                        String type = node.get(0).asText();

                        // 数组内容为风格
                        if ("font".equalsIgnoreCase(type)) {
                            msgBody.setMsgStyle(Jacksons.deserialize(node.get(1).toString(), MsgStyle.class));

                            // 数组内容为表情
                        } else if ("face".equalsIgnoreCase(type)) {
                            msgBody.addElement(MsgElement.createFaceElement(node.get(1).asInt(1)));

                            // 数组内容为离线图片对象
                        } else if ("offpic".equalsIgnoreCase(type)) {
                            JsonNode offpic = node.get(1);

                            msgBody.addElement(MsgElement.createOffPicElement(offpic.get("success").asBoolean(), offpic.get("file_path").asText()));
                        } else {
                            logger.warn("未知消息: {}", node);
                        }
                    } else {
                        logger.warn("未知消息: {}", node);
                    }
                }
            }
            return msgBody;
        }
    }

    /**
     * 消息体序列化器, 将消息体中 样式/ 元素 转换为 QQ 所使用的数组
     */
    static final class MsgBodySerializer extends JsonSerializer<MsgBody> {
        @Override
        public void serialize(MsgBody value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
            jgen.writeStartArray();
            if (value != null) {
                for (MsgElement fragment : value) {
                    if (fragment instanceof MsgElement.TextElement) {
                        jgen.writeString(((MsgElement.TextElement) fragment).getText());
                    } else if (fragment instanceof MsgElement.FaceElement) {
                        // 表情
                        jgen.writeStartArray();
                        jgen.writeString("face");
                        jgen.writeNumber(((MsgElement.FaceElement) fragment).getId());
                        jgen.writeEndArray();
                    } else {
                        // TODO 对于离线图片等如何处理??
                    }
                }
                // 字体 在发送消息中需要放在最后(否则字体后的内容会被忽略)
                jgen.writeStartArray();
                jgen.writeString("font");
                jgen.writeObject(value.getMsgStyle());
                jgen.writeEndArray();
            }
            jgen.writeEndArray();
        }
    }
}
